package cn.elead.it.sso.core.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.elead.it.sso.core.constant.GlobalVariable;
import cn.elead.it.sso.core.login.SsoWebLoginHelper;
import cn.elead.it.sso.core.model.SsoResponse;
import cn.elead.it.sso.core.model.SsoUser;
import cn.elead.it.sso.core.path.AntPathMatcher;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

/**
 * 基于web cookie模式的客户端过滤器
 * 
 * @author luopeng
 *
 */
@SuppressWarnings("serial")
public class SsoWebFilter extends SsoFilter {

	private static Logger logger = LoggerFactory.getLogger(SsoWebFilter.class);

	private static final AntPathMatcher antPathMatcher = new AntPathMatcher();

	private String ssoServer;
	private String logoutPath;
	private String clientId;
	// private String clientSecret;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {

		ssoServer = filterConfig.getInitParameter(GlobalVariable.SSO_SERVER);
		logoutPath = filterConfig.getInitParameter(GlobalVariable.SSO_LOGOUT_PATH);
		clientId = filterConfig.getInitParameter(GlobalVariable.SSO_CLIENTID);
		// clientSecret =
		// filterConfig.getInitParameter(GlobalVariable.SSO_CLIENTSECRET);

		logger.info("SsoWebFilter init.");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;

		// make url
		String servletPath = req.getServletPath();

		// excluded path check
		for (String excludedPath : excludedPaths) {
			String uriPattern = excludedPath.trim();

			// 支持ANT表达式
			if (antPathMatcher.match(uriPattern, servletPath)) {
				// excluded path, allow
				chain.doFilter(request, response);
				return;
			}

		}

		// logout path check
		if (logoutPath != null && logoutPath.trim().length() > 0 && logoutPath.equals(servletPath)) {

			// remove cookie
			SsoWebLoginHelper.removeSessionIdByCookie(req, res);

			// redirect logout
			// total link
			String link = req.getRequestURL().toString();
			link = StrUtil.replace(link, GlobalVariable.SSO_LOGOUT, "/");
			String logoutPageUrl = ssoServer.concat(GlobalVariable.SSO_LOGOUT) + "?" + GlobalVariable.CLIENT_ID + "="
					+ clientId + "&" + GlobalVariable.REDIRECT_URI + "=" + link;
			res.sendRedirect(logoutPageUrl);
			return;
		}

		// valid login user, cookie + redirect
		SsoUser ssoUser = SsoWebLoginHelper.loginCheck(req, res);

		// valid login fail
		if (ssoUser == null) {
			String header = req.getHeader("content-type");
			boolean isJson = header != null && header.contains("json");
			if (isJson) {
				writeValueAsJson(response, new SsoResponse().setStatus(401).setMsg("sessionId已失效"));
				return;
			} else {
				// total link
				String link = req.getRequestURL().toString();
				// redirect logout
				String loginPageUrl = ssoServer.concat(GlobalVariable.SSO_LOGIN) + "?" + GlobalVariable.CLIENT_ID + "="
						+ clientId + "&" + GlobalVariable.REDIRECT_URI + "=" + link;
				res.sendRedirect(loginPageUrl);
				return;
			}

		}
		/*
		 * String secret = ssoUser.getClientSecret(); ssoUser.setClientSecret(null); //
		 * 判断客户端秘钥是否一致 if (!StrUtil.equalsIgnoreCase(secret, clientSecret)) {
		 * writeValueAsJson(response, new
		 * SsoResponse().setStatus("400").setMsg("clientSecret不正确!")); return; }
		 */

		// ser sso user
		request.setAttribute(GlobalVariable.SSO_USER, ssoUser);
		request.setAttribute("API_UID", ssoUser.getUserId());

		// already login, allow
		chain.doFilter(request, response);
		return;
	}

	/**
	 * 向外输出json对象
	 *
	 * @param obj
	 */
	public void writeValueAsJson(ServletResponse response, Object obj) {
		if (response.isCommitted()) {
			logger.warn("Warn: Response isCommitted, Skip the implementation of the method.");
			return;
		}
		response.setContentType("application/json;charset=utf-8");
		response.setCharacterEncoding(StandardCharsets.UTF_8.name());
		try (PrintWriter writer = response.getWriter()) {
			writer.print(JSONUtil.toJsonStr(obj));
			writer.flush();
		} catch (IOException e) {
			logger.warn("Error: Response printJson faild, stackTrace: {}", e);
		}
	}

}
